Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Verify definitions #116

Open
wants to merge 36 commits into
base: main
Choose a base branch
from
Open

Verify definitions #116

wants to merge 36 commits into from

Conversation

tirix
Copy link
Collaborator

@tirix tirix commented Jun 8, 2023

This is an in progress version of a pull request adding the definition soundness checks.
All checks are not implemented yet, and errors are not handled (the function panics if anything goes wrong).

The intend is to follow the algorithm provided by @digama0 in #103 to identify definitions.

Based on the identification of definitions, this also adds a function to export the dependencies of definition into a GraphML file format. Redundant dependencies are not checked (for example, df-ipf includes two conjunctions, so the edge between df-ipf and df-an is doubled).

Currently this algorithm fails for these reasons:

  • the axiom ax-hilex is introduced while there are still several definitions pending (e.g. csh is defined before, but df-sh comes after), which breaks the assumption that definition immediately follow the syntax axioms,
  • the axiom ax-riotaBAD is a redefinition of crio. There should be only one definition for a given definiendum.
  • the syntax axiom cmesy for mESyn does not have a definition

@tirix
Copy link
Collaborator Author

tirix commented Jun 8, 2023

@david-a-wheeler Sorry this is kind of overrules your #103 , but there seemed to be some kind of urgency in introducing these changes now.

@david-a-wheeler
Copy link
Member

@tirix - no problem! I started writing definitional soundness code because I wanted the functionality, but I always seem to "run out of time" to complete it. Thanks for picking up the effort, I'm delighted to see it.

@tirix tirix requested a review from digama0 June 8, 2023 22:48
@tirix tirix marked this pull request as ready for review June 8, 2023 22:48
@tirix
Copy link
Collaborator Author

tirix commented Jun 8, 2023

@digama0 Could you please confirm that this corresponds to what you were describing?

Copy link
Collaborator Author

@tirix tirix left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all the improvements!
I only have one question.

src/defck.rs Outdated Show resolved Hide resolved
@digama0
Copy link
Member

digama0 commented Jun 12, 2023

I pushed some more modifications, the current error reports are basically all true positives now, and it might help to start working on them in parallel with the checker itself. Summary of issues:

  • The line $( $j primitive 'weq' 'wel'; $) marks non-primitives as primitive, which is somewhere between superfluous and an error
  • chba $a class ~H $. is not marked as primitive (NM)
  • cmgfs $a class mGFS $. is missing a definition (@digama0)
  • cmesy $a class mESyn $. is missing a definition (@digama0)
  • cqpOLD $a class QpOLD $. is missing a definition (@digama0)
  • cprvb $a wff Prv ph $. is missing a primitive declaration (@benjub)
  • wcel-wl $a wff x wl-el B $. and wcel2-wl $a wff x wl-el2 B $. are missing a primitive declaration (@wlammen)
  • wvhc4 .. wvhc12 are missing definitions (AS)

src/defck.rs Outdated Show resolved Hide resolved
src/diag.rs Outdated Show resolved Hide resolved
src/diag.rs Outdated
Comment on lines 497 to 507
DefCkSyntaxUsedBeforeDefinition(tok, saddr) => (format!("Definition Check: '{label}' used before definition", label = t(tok)).into(), vec![(
AnnotationType::Error,
format!("this expression contains an occurrence of '{label}'", label = t(tok)).into(),
stmt,
stmt.span(),
), (
AnnotationType::Note,
"syntax declared here".into(),
sset.statement(*saddr),
sset.statement(*saddr).label_span(),
)]),
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice if we could point to the definition if there is one.

src/diag.rs Outdated Show resolved Hide resolved
src/defck.rs Outdated
Comment on lines 381 to 388
let free_dummies = free_dummies
.into_iter()
.map(|atom| {
let sref = self.db.statement_by_label(atom).unwrap();
sref.math_at(1).slice.into()
})
.sorted()
.collect();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One of the things I don't like about the current Formula interface is that variables are represented as $f theorem labels, which makes it difficult to interact with Frame for e.g. DV condition checking (which uses variable indexes and $v Atoms for representing variables); you have to go through this kind of rigamarole to turn those $f labels into variable names.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tirix There seems to be a bug in the grammar parsing, related to this: the statement parse for df-tru contains vx nodes even though vx is not in scope and has not been defined yet. The actual $f in the context is vx.tru.

Copy link
Collaborator Author

@tirix tirix Jun 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concerning df-tru here is how the grammar parsing works:
The grammar module's FormulaTokenIterator gets the atom for each token using nameck's lookup_symbol:

            if let Some(l) = self.nset.lookup_symbol(t.as_bytes()) { ... }

It later uses lookup_float to get the float if happens to be variable. In none of these calls grammar can specify a frame context, and nameck actually only stores the topmost statement for a given token.

@digama0
Copy link
Member

digama0 commented Jun 12, 2023

We have several applications relying on metamath-knife, and it's always better if they can point to something stable interface-wise.

Note that the API for definition checking changes in every commit, I wouldn't commit to anything until it's feature-complete. And it has some effects on the Formula API too, since this is the first kind of real theorem-prover-ish thing we are trying to do with metamath-knife inside the main repo.

@digama0
Copy link
Member

digama0 commented Jun 12, 2023

If it implements only some of the rules, but you can invoke the code to check those rules, I suggest merging it.

That will give us a more-stable base to build on.

For clarity perhaps we should document "incomplete implementation" in the help info, to make it clear that it only implements some of the checks. That way no one will accidentally depend on it being the full implementation.

When it comes to writing a verifier, I don't like releasing it half baked when only some of the checks required for soundness are implemented. There is a very concrete end point for the implementation. If we want to release something incomplete, then it should err on the side of more false positives, but we already know that this will cause thousands of errors in set.mm so it won't be so helpful.

@digama0
Copy link
Member

digama0 commented Jun 13, 2023

Things are almost done now. All the DV checks are implemented, as well as the axiom / def naming checker, which revealed some additional issues that have been pushed to metamath/set.mm#3247 (in particular I put some things as primitive that were actually defined but where the definition was far away from the syntax and other disallowed stuff was in between). There are now three (expected) errors:

warning: Axioms should start with 'ax-'
     --> ../mm/set.mm:24406:3
      |
24406 |   df-clab $a |- ( x e. { y | ph } <-> [ x / y ] ph ) $.
      |   ------- This was identified as an axiom, but it doesn't start with 'ax-'
      |
warning: Axioms should start with 'ax-'
     --> ../mm/set.mm:24478:5
      |
24478 |     df-cleq $a |- ( A = B <-> A. x ( x e. A <-> x e. B ) ) $.
      |     ------- This was identified as an axiom, but it doesn't start with 'ax-'
      |
warning: Axioms should start with 'ax-'
     --> ../mm/set.mm:24547:5
      |
24547 |     df-clel $a |- ( A e. B <-> E. x ( x = A /\ x e. B ) ) $.
      |     ------- This was identified as an axiom, but it doesn't start with 'ax-'
      |

which is basically what I've been saying all along. Options now are to add some kind of override, or change the names.

@tirix
Copy link
Collaborator Author

tirix commented Jun 13, 2023

Options now are to add some kind of override, or change the names.

This deserves a wider discussion.
I think Norm wanted to keep the ax- prefix for actual axioms of set theory, so I prefer the former.

At least df-cleq can clearly be linked with the wceq syntax, and df-clel with wcel, why do they need to be declared primitives?
For df-clab, obviously it's a special case.

Interestingly a definition command appears in set.mm, even though the metamath-knife def checker does not use it:

  $( Register '<->' as an equality for its type (wff). $)
  $( $j
    equality 'wb' from 'biid' 'bicomi' 'bitri';
    definition 'dfbi1' for 'wb';
  $)

I did not find its trace in MMJ2. Did I miss something?

@tirix
Copy link
Collaborator Author

tirix commented Jun 13, 2023

Interestingly a definition command appears in set.mm

Actually this is defined in j_syntax.html:

$j definition 'DEFTHM' for 'SYNTAX';

Declare a theorem to be a definition. DEFTHM is a $p statement which represents an alternative definition for the syntax represented by the $a statement SYNTAX. The definition should have a top level equality declared by the equality command with the definition on the right hand side. (This command is only needed when the definition does not immediately follow the syntax itself, which in set.mm only occurs for df-bi. For most definitions we can
automatically infer the requisite structure.)

@digama0
Copy link
Member

digama0 commented Jun 13, 2023

At least df-cleq can clearly be linked with the wceq syntax, and df-clel with wcel, why do they need to be declared primitives?

The answer to this is basically given by the same tool that is producing the output above. Being 'linked' to an axiom that does not match the requirements for a definition is not sufficient. In fact, the ax/df check is done early, before we have even done most of the fancy work on definitions: df-cleq fails immediately for failing the test "it introduces exactly one new symbol and is the first axiom to refer to that symbol". wceq has been used for hundreds of prior theorems before df-cleq comes along so it is obviously ineligible. The story is the same for df-clel.

Interestingly a definition command appears in set.mm, even though the metamath-knife def checker does not use it:

This was part of an alternative design for the definition justification checker, which would parse the definition theorem to supply the definition body, and then ensure that the justification matches. In the design implemented here, the justification is unified against the definitional axiom to obtain the LHS -> RHS mapping, so the definition is not needed. We can validate it if you think it is worth it though.

@jkingdon
Copy link
Contributor

Options now are to add some kind of override, or change the names.

I would be a bit disappointed if we get stuck on which of these two to choose and end up not getting the definition verifier merged.

Based on my limited understanding, I guess an override is what we have been doing (maybe expressed in words, maybe in the mmj2 definition checker), and a name change is seemingly more intellectually honest in light of things like https://us.metamath.org/mpeuni/bj-ax8.html .

Disclaimer: although I have looked at things like https://math.stackexchange.com/questions/231087/what-can-i-do-with-proper-classes and https://en.wikipedia.org/wiki/Zermelo%E2%80%93Fraenkel_set_theory#Virtual_classes I'm not sure I understand this fully. I do gather that df-clab , df-clel , and df-cleq do not give us the ability to (say) quantify over classes, so in that sense the classes are still virtual. And I suppose maybe it would be true that one way out would be separate notations for = and e. for sets versus classes (like we already have for [ versus [.). I don't know how much of the problem this would solve, but I do suspect it would be inconvenient, or at least require changing a lot of proofs.

I'm not aware of any quick fix other than "some kind of override, or change the names" so we probably are left with those two choices for now regardless of what we do longer term.

@digama0
Copy link
Member

digama0 commented Jun 20, 2023

Quick comment, this PR isn't blocked on that issue (alone), I have some local work which continues the main implementation which got pushed off of my "to do immediately" list by something else, but which I plan to return to soon. I did prepare a version which just stubs out the missing part of the checker so that it could be merged, but as expected this leaves about 1300 errors, so it won't be immediately usable.

@jkingdon
Copy link
Contributor

Quick comment, this PR isn't blocked on that issue (alone)

Thanks for the clarification. I'm mostly thinking of trying to coordinate:

  1. The definition work (however much of it we are able/interested in merging soon)
  2. Splitting into two or more crates, and
  3. Adding the checker for $j usage

Not that we have a detailed plan for exactly who does all of this and how but those seem like three of the most wanted enhancements that I've noticed.

@digama0
Copy link
Member

digama0 commented Jun 20, 2023

I'd prefer to wait on (2) until most of the in-flight additions have been merged. For (3) I think it can be worked on independently of this issue, they are not really conflicting.

@jkingdon
Copy link
Contributor

I'd prefer to wait on (2) until most of the in-flight additions have been merged. For (3) I think it can be worked on independently of this issue, they are not really conflicting.

Makes sense. Looks like (2) is being discussed at #117 and (3) has a pull request at #118 .

@tirix
Copy link
Collaborator Author

tirix commented Nov 27, 2023

I'm in favor of merging this first, and handling the remaining questions over df-clab, df-clel and df-cleq separately.

If this is merged, we could already implement a metamath-knife based definition checker in set.mm`s CI by just ignoring the 3 exceptions, until they are resolved.

@jkingdon
Copy link
Contributor

I'm in favor of merging this first, and handling the remaining questions over df-clab, df-clel and df-cleq separately.

Just to confirm something I think I know the answer to: is the definition checker complete (assuming that it isn't supposed to handle those three)? That is, does it implement the rules at "Additional rules for definitions" in https://us.metamath.org/mpeuni/conventions.html ?

If this is merged, we could already implement a metamath-knife based definition checker in set.mm`s CI by just ignoring the 3 exceptions, until they are resolved.

I mean, this is what we do for mmj2, right? If so, it is hard to see merging this, and adding to CI, as a step backward.

@digama0
Copy link
Member

digama0 commented Nov 27, 2023

Since I have had a WIP commit sitting in my local copy for too long, I've pushed it to tirix/metamath-knife@verify_definitions...metamath:metamath-knife:verify_definitions_2 .

@tirix
Copy link
Collaborator Author

tirix commented Nov 28, 2023

So would @digama0 you like me to create a pull request with those changes, review them, and merge them to this branch?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants